package vip.ola.pay.channel.abc;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import vip.ola.core.common.constant.PayConstant;
import vip.ola.core.common.util.MyLog;
import vip.ola.core.common.util.PayDigestUtil;
import vip.ola.core.common.util.PayUtil;
import vip.ola.core.entity.PayOrder;
import vip.ola.core.entity.PayPassageAccount;
import vip.ola.pay.channel.BasePayment;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;

import static vip.ola.core.common.constant.Constant.UTF8;
import static vip.ola.core.common.constant.PayConstant.*;
import static vip.ola.core.common.constant.PayEnum.ERR_0010;
import static vip.ola.core.common.constant.PayEnum.ERR_0121;
import static vip.ola.core.common.util.LocalDateTimeUtil.DATETIME_FORMATTER_NONE;

/**
 * @author: dingzhiwei
 * @date: 17/12/24
 * @description:
 */
@Service
public class AbcPaymentService extends BasePayment {

    private static final MyLog _log = MyLog.getLog(AbcPaymentService.class);

    @Override
    public String getChannelName() {
        return PayConstant.CHANNEL_NAME_CODE;
    }

    @Override
    public JSONObject pay(PayOrder payOrder) {
        try {
            System.out.println("abc支付使用子账号ID：" + payOrder.getChannelMchId());
            PayPassageAccount payPassageAccount = rpcCommonService.rpcPayPassageAccountService.findById(payOrder.getPassageAccountId());
            if (payPassageAccount == null || StringUtils.isBlank(payPassageAccount.getParam())) {
                return PayUtil.makeRetFail(ERR_0121);
            }
            JSONObject accountParams = JSONObject.parseObject(payPassageAccount.getParam());
            JSONObject params = new JSONObject();
            params.put("merchant_id", payPassageAccount.getPassageMchId());
            params.put("version", "V2.0");
            params.put("pay_type", accountParams.getString("pay_type"));
            params.put("device_type", "wap");
            params.put("request_time", DATETIME_FORMATTER_NONE.format(LocalDateTime.now()));
            params.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
            params.put("pay_ip", accountParams.getString("pay_ip"));
            params.put("out_trade_no", payOrder.getMchOrderNo());
            params.put("amount", new BigDecimal(payOrder.getAmount()).divide(new BigDecimal(100)).setScale(2));
            params.put("notify_url", accountParams.getString("notify_url"));
            String sign = getSign(params, payPassageAccount.getPrivateKey()).toUpperCase();
            params.put("sign", sign);
            String payUrl = accountParams.getString("payUrl");
            String retStr = call(payUrl, params);
            _log.info("调用Abc返回结果：" + retStr);
            JSONObject retObj = JSONObject.parseObject(retStr);
            if ("success".equals(retObj.getString("status"))) {
                String retSign = retObj.getString("sign");
                retObj.remove("sign");
                if (retSign.equals(getSign(retObj, payPassageAccount.getPrivateKey()).toUpperCase())) {
                    int result = rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
                    _log.info("更新订单状态为支付中: result={}", result);
                    return PayUtil.makeRetPayUrl(retObj.getString("pay_url"), null);
                } else {
                    int result = rpcCommonService.rpcPayOrderService.updateStatus4Fail(payOrder.getPayOrderId(), PAY_STATUS_INIT,
                            retObj.getString("message"), retObj.getString("message"));
                    _log.info("更新订单状态为支付失败: result={}", result);
                    return PayUtil.makeRetFail(ERR_0010);
                }
            } else {
                int result = rpcCommonService.rpcPayOrderService.updateStatus4Fail(payOrder.getPayOrderId(), PAY_STATUS_INIT,
                        retObj.getString("message"), retObj.getString("message"));
                _log.info("更新订单状态为支付失败: result={}", result);
                return PayUtil.makeRetFail(ERR_0010);
            }
        } catch (Exception e) {
            _log.error(e, "调用ABC渠道异常。");
            return PayUtil.makeRetFail(ERR_0010);
        }
    }

    @Override
    public JSONObject query(PayOrder payOrder) {
        try {
            PayPassageAccount payPassageAccount = rpcCommonService.rpcPayPassageAccountService.findById(payOrder.getPassageAccountId());
            if (payPassageAccount == null || StringUtils.isBlank(payPassageAccount.getParam())) {
                return PayUtil.makeRetFail(ERR_0121);
            }
            JSONObject params = new JSONObject();
            params.put("merchant_id", payPassageAccount.getPassageMchId());
            params.put("version", "V2.0");
            params.put("request_time", DATETIME_FORMATTER_NONE.format(LocalDateTime.now()));
            params.put("nonce_str", UUID.randomUUID());
            String sign = getSign(params, payPassageAccount.getPrivateKey()).toUpperCase();
            params.put("sign", sign);

            JSONObject accountParams = JSONObject.parseObject(payPassageAccount.getParam());
            String queryUrl = accountParams.getString("queryUrl");
            String retStr = call(queryUrl, params);
            JSONObject retObj = JSONObject.parseObject(retStr);
            if ("success".equals(retObj.getString("status"))) {
                String retSign = retObj.getString("sign");
                retObj.remove("sign");
                if (retSign.equals(getSign(retObj, payPassageAccount.getPrivateKey()).toUpperCase())) {
                    return PayUtil.makeRetSuc();
                } else {
                    int result = rpcCommonService.rpcPayOrderService.updateStatus4Fail(payOrder.getPayOrderId(), PAY_STATUS_INIT,
                            retObj.getString(RESULT_PARAM_ERRCODE), retObj.getString(RESULT_PARAM_ERRDES));
                    _log.info("更新订单状态为支付失败: result={}", result);
                    return PayUtil.makeRetFail(ERR_0010);
                }
            } else {
                int result = rpcCommonService.rpcPayOrderService.updateStatus4Fail(payOrder.getPayOrderId(), PAY_STATUS_INIT,
                        retObj.getString(RESULT_PARAM_ERRCODE), retObj.getString(RESULT_PARAM_ERRDES));
                _log.info("更新订单状态为支付失败: result={}", result);
                return PayUtil.makeRetFail(ERR_0010);
            }
        } catch (Exception e) {
            return PayUtil.makeRetFail(ERR_0010);
        }
    }

    public static String call(String url, Map param) {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpPost httpPost = new HttpPost(url);
        // 响应模型
        CloseableHttpResponse response = null;
        String responseContext = null;
        try {
            StringEntity entity = new StringEntity(JSONObject.toJSONString(param), ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 由客户端执行(发送)Get请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            if (responseEntity != null) {
                responseContext = EntityUtils.toString(responseEntity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return responseContext;
    }

    protected static String getSign(Map<String, Object> map, String key) {
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null != entry.getValue() && !"".equals(entry.getValue())) {
                if (entry.getValue() instanceof JSONObject) {
                    list.add(entry.getKey() + "=" + PayDigestUtil.getSortJson((JSONObject) entry.getValue()) + "&");
                } else {
                    list.add(entry.getKey() + "=" + entry.getValue() + "&");
                }
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result = result.substring(0, result.lastIndexOf("&"));
        result += key;
        _log.info("Sign Before MD5:" + result);
        result = PayDigestUtil.md5(result, UTF8).toUpperCase();
        _log.info("Sign Result:" + result);
        return result;
    }

    @Override
    public JSONObject close(PayOrder payOrder) {
        return null;
    }

}
